import type { IScriptData, IUserData } from './types'
import { IconService } from '../../../../../../../../../lib/icons'
import { ICON_IDS } from '../../../../../../../../../lib/icons/types/constants'
import { PageHandler } from '../../../../../../../../../lib/page_handler'
import { ToolKit } from '../../../../../../../../../lib/utils/toolkit'
import {
  AppStyleCollections,
  BodyClasses,
  loggerDeduplicator,
  MODULE_CONFIG,
} from '../../../../../../../../../types/constants'
import { TAMPERMONKEY_INSTALL_URL_TEMPLATE } from '../../../../../../../../../types/constants/web_link'
import { SYMBOLS } from '../../../../../../../../../types/interfaces'
import { GreasyFork } from '../../page/lib'
import { HIGH_SCORE_THRESHOLD } from './types'

export class ScriptProcessor {
  readonly name: string = 'ScriptProcessor'
  readonly processedAttr: string = 'processed-base'
  private static instance: ScriptProcessor
  private pageHandler: PageHandler = PageHandler.getInstance()
  private iconService: IconService = IconService.getInstance()
  readonly SCRIPT_LIST_SELECTOR: string = this.pageHandler.services.greasyFork.getScriptListSelector()

  /**
   * 获取单例实例
   */
  public static getInstance(): ScriptProcessor {
    if (!ScriptProcessor.instance) {
      ScriptProcessor.instance = new ScriptProcessor()
    }
    return ScriptProcessor.instance
  }

  init(): void {
    this.processAllScriptElements()
  }

  /**
   * 处理所有脚本元素
   */
  processAllScriptElements(): void {
    const $elements = $(this.SCRIPT_LIST_SELECTOR)

    if (!$elements || $elements.length === 0) {
      loggerDeduplicator.error(`[${this.name}] 没有找到脚本列表元素：${this.SCRIPT_LIST_SELECTOR}`)
      return
    }

    // 处理每个脚本元素
    $elements.each((index, element) => {
      this.processScriptElement(index, $(element))
    })
  }

  /**
   * 处理单个脚本元素
   */
  processScriptElement(index: number, $element: JQuery<HTMLElement>): void {
    // 检查是否已经处理过（避免重复处理）
    if ($element.data(this.processedAttr))
      return

    $element.data(this.processedAttr, true)

    // 从元素获取数据
    const scriptId = GreasyFork.getCurrentScriptIdFromList($element)
    const data: IScriptData = this.getScriptData($element)

    // 添加用户头像
    this.addAvatar($element, data)
    // 添加安装图标
    this.addInstallIcon($element)
    // 添加脚本序号
    this.pageHandler.pages.base.addIndex(index, $element)
    // 添加版本信息
    $element.find('dd.script-list-updated-date').append(
      `<span style="margin-left: 8px;"> ${ToolKit.ui.element.generateLinkElement(`v${data.version}`, `${data.url}/versions`)}</span>`,
    )
    // 点击评分跳转到反馈页面
    $element.find('dd.script-list-ratings').on('click', () => {
      if (scriptId.length === 0)
        return

      ToolKit.browser.url.openNewTab(MODULE_CONFIG.URL.greasyFork.feedbackUrl.replace('%s', scriptId))
    })
  }

  /**
   * 添加用户头像
   */
  addAvatar($element: JQuery<HTMLElement>, data: IScriptData): void {
    const authorData: IUserData = {
      author: data.author,
      authorUrl: data.authorUrl,
    }

    this.pageHandler.features.user.addAvatar($element, authorData)
  }

  /**
   * 添加安装图标
   */
  addInstallIcon($element: JQuery<HTMLElement>): void {
    const $link = $element.find('.script-link')
    const scriptCodeLink = $element.attr('data-code-url') || ''

    const $installIcon = $(`
      <a class="script-install-icon" aria-hidden="true" href="${scriptCodeLink || ''}" target="_blank">  
        ${this.iconService.api.icon.asSvg(ICON_IDS.action.install, { size: 24 })}
      </a>
    `)

    $link.prepend($installIcon)

    $installIcon.on('click', (e) => {
      e.preventDefault()
      e.stopPropagation()

      ToolKit.browser.url.openNewTab(`${TAMPERMONKEY_INSTALL_URL_TEMPLATE}${scriptCodeLink}`)
    })
  }

  /**
   * 更新用户头像
   */
  updateAvatar($element: JQuery<HTMLElement>): void {
    const isHighScore = Number.parseInt($element.find('.score-ring .score-value').text().trim() || '0') > HIGH_SCORE_THRESHOLD
    const $highTotalInstalls = $element.find('dd.total-installs.high, dd.daily-installs.high')

    if (isHighScore || $highTotalInstalls.length) {
      const $avatarContainer = $element.find(`.${AppStyleCollections.Body.AVATAR_CONTAINER}`)

      $avatarContainer.find('.avatar').attr('src', this.iconService.api.icon.asDataUrl(ICON_IDS.user.avatarGold, { size: 36 }))
      $avatarContainer.find('.avatar-name')
        .attr('title', this.generateUserAchievement(isHighScore, $element))
        .addClass(this.pageHandler.services.greasyFork.scriptStarClass)
    }
  }

  /**
   * 生成用户成就
   */
  generateUserAchievement(highScore: boolean, $element: JQuery<HTMLElement>): string {
    const userAchievements: string[] = []
    if (highScore)
      userAchievements.push('高评分')
    if ($element.length)
      userAchievements.push('高安装量')

    return userAchievements.length > 0
      ? `${SYMBOLS.USER.ADMIN} 脚本大神（产出${userAchievements.join('、')}优质脚本）`
      : `${SYMBOLS.NATURE.FIRE} 优质作者`
  }

  getScriptData($element: JQuery<HTMLElement>): IScriptData {
    const totalInstalls = Number.parseInt($element.attr('data-script-total-installs') || '0')
    const createDays = this.calculateDaysSince($element.attr('data-script-created-date'))
    const dailyAvgInstalls = this.clacDailyAvgInstalls(totalInstalls, createDays)

    return {
      url: $element.find('.script-link').attr('href') || '',
      author: $element.find('dd.script-list-author span > a').text().trim(),
      authorUrl: $element.find('dd.script-list-author span > a').attr('href') || '',
      goodRating: Number.parseInt($element.find('.good-rating-count').text() || '0'),
      okRating: Number.parseInt($element.find('.ok-rating-count').text() || '0'),
      badRating: Number.parseInt($element.find('.bad-rating-count').text() || '0'),
      dailyInstalls: Number.parseInt($element.attr('data-script-daily-installs') || '0'),
      totalInstalls,
      dailyAvgInstalls,
      lastUpdatedDays: this.calculateDaysSince($element.attr('data-script-updated-date')),
      createDays,
      version: $element.attr('data-script-version') || '未知',
      isMine: $element.find('.script-creator-badge').hasClass(BodyClasses.IS_MINE),
    }
  }

  /**
   * 计算从日期时间到现在的天数
   */
  calculateDaysSince(dateString: string | undefined): number {
    if (!dateString)
      return 999

    const updateDate = new Date(dateString)
    const now = new Date()
    return Math.floor((now.getTime() - updateDate.getTime()) / (1000 * 60 * 60 * 24))
  }

  /**
   * 计算日均安装量（从创建时间开始计算）
   * @param totalInstalls 总安装量
   * @param createDays 创建时间
   */
  clacDailyAvgInstalls(totalInstalls: number, createDays: number): number {
    return createDays > 0 ? Math.round(totalInstalls / createDays) : 0
  }

  styles(): string {
    return `
.script-link:has(.script-install-icon) {
  display: inline-flex;
  align-items: center;
  gap: 4px;

  .script-install-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0; /* 防止图标被压缩 */
  }
}
    `
  }
}
